home *** CD-ROM | disk | FTP | other *** search
/ Enter 2006 September / Enter 09 2006.iso / Internet / SpamExperts Home 1.1 / SpamExperts Home.exe / lib / spamexperts.modules / spambayes / OptionsClass.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2006-07-14  |  26.2 KB  |  860 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. '''OptionsClass
  5.  
  6. Classes:
  7.     Option - Holds information about an option
  8.     OptionsClass - A collection of options
  9.  
  10. Abstract:
  11.  
  12. This module is used to manage "options" managed in user editable files.
  13. This is the implementation of the Options.options globally shared options
  14. object for the SpamBayes project, but is also able to be used to manage
  15. other options required by each application.
  16.  
  17. The Option class holds information about an option - the name of the
  18. option, a nice name (to display), documentation, default value,
  19. possible values (a tuple or a regex pattern), whether multiple values
  20. are allowed, and whether the option should be reset when restoring to
  21. defaults (options like server names should *not* be).
  22.  
  23. The OptionsClass class provides facility for a collection of Options.
  24. It is expected that manipulation of the options will be carried out
  25. via an instance of this class.
  26.  
  27. Experimental or deprecated options are prefixed with \'x-\', borrowing the
  28. practice from RFC-822 mail.  If the user sets an option like:
  29.  
  30.     [Tokenizer]
  31.     x-transmogrify: True
  32.  
  33. and an \'x-transmogrify\' or \'transmogrify\' option exists, it is set silently
  34. to the value given by the user.  If the user sets an option like:
  35.  
  36.     [Tokenizer]
  37.     transmogrify: True
  38.  
  39. and no \'transmogrify\' option exists, but an \'x-transmogrify\' option does,
  40. the latter is set to the value given by the users and a deprecation message
  41. is printed to standard error.
  42.  
  43. To Do:
  44.  o Stop allowing invalid options in configuration files
  45.  o Find a regex expert to come up with *good* patterns for domains,
  46.    email addresses, and so forth.
  47.  o str(Option) should really call Option.unconvert since this is what
  48.    it does.  Try putting that in and running all the tests.
  49.  o [See also the __issues__ string.]
  50.  o Suggestions?
  51.  
  52. '''
  53. __credits__ = 'All the Spambayes folk.'
  54. __issues__ = 'Things that should be considered further and by\nother people:\n\nWe are very generous in checking validity when multiple values are\nallowed and the check is a regex (rather than a tuple).  Any sequence\nthat does not match the regex may be used to delimit the values.\nFor example, if the regex was simply r"[\\d]*" then these would all\nbe considered valid:\n"123a234" -> 123, 234\n"123abced234" -> 123, 234\n"123XST234xas" -> 123, 234\n"123 234" -> 123, 234\n"123~!@$%^&@234!" -> 123, 234\n\nIf this is a problem, my recommendation would be to change the\nmultiple_values_allowed attribute from a boolean to a regex/None\ni.e. if multiple is None, then only one value is allowed.  Otherwise\nmultiple is used in a re.split() to separate the input.\n'
  55. import sys
  56. import os
  57. import shutil
  58. from tempfile import TemporaryFile
  59.  
  60. try:
  61.     import cStringIO as StringIO
  62. except ImportError:
  63.     import StringIO
  64.  
  65. import re
  66. import types
  67. import locale
  68.  
  69. try:
  70.     (True, False, bool)
  71. except NameError:
  72.     (True, False) = (1, 0)
  73.     
  74.     def bool(val):
  75.         return not (not val)
  76.  
  77.  
  78.  
  79. try:
  80.     import textwrap
  81. except ImportError:
  82.     
  83.     def wrap(s):
  84.         length = 40
  85.         return [ s[i:i + length].strip() for i in xrange(0, len(s), length) ]
  86.  
  87.  
  88. wrap = textwrap.wrap
  89. __all__ = [
  90.     'OptionsClass',
  91.     'HEADER_NAME',
  92.     'HEADER_VALUE',
  93.     'INTEGER',
  94.     'REAL',
  95.     'BOOLEAN',
  96.     'SERVER',
  97.     'PORT',
  98.     'EMAIL_ADDRESS',
  99.     'PATH',
  100.     'VARIABLE_PATH',
  101.     'FILE',
  102.     'FILE_WITH_PATH',
  103.     'IMAP_FOLDER',
  104.     'IMAP_ASTRING',
  105.     'RESTORE',
  106.     'DO_NOT_RESTORE',
  107.     'IP_LIST']
  108. MultiContainerTypes = (types.TupleType, types.ListType)
  109.  
  110. class Option(object):
  111.     
  112.     def __init__(self, name, nice_name = '', default = None, help_text = '', allowed = None, restore = True):
  113.         self.name = name
  114.         self.nice_name = nice_name
  115.         self.default_value = default
  116.         self.explanation_text = help_text
  117.         self.allowed_values = allowed
  118.         self.restore = restore
  119.         self.delimiter = None
  120.         self.set(default)
  121.  
  122.     
  123.     def display_name(self):
  124.         '''A name for the option suitable for display to a user.'''
  125.         return self.nice_name
  126.  
  127.     
  128.     def default(self):
  129.         '''The default value for the option.'''
  130.         return self.default_value
  131.  
  132.     
  133.     def doc(self):
  134.         '''Documentation for the option.'''
  135.         return self.explanation_text
  136.  
  137.     
  138.     def valid_input(self):
  139.         '''Valid values for the option.'''
  140.         return self.allowed_values
  141.  
  142.     
  143.     def no_restore(self):
  144.         '''Do not restore this option when restoring to defaults.'''
  145.         return not (self.restore)
  146.  
  147.     
  148.     def set(self, val):
  149.         '''Set option to value.'''
  150.         self.value = val
  151.  
  152.     
  153.     def get(self):
  154.         '''Get option value.'''
  155.         return self.value
  156.  
  157.     
  158.     def multiple_values_allowed(self):
  159.         '''Multiple values are allowed for this option.'''
  160.         return type(self.default_value) in MultiContainerTypes
  161.  
  162.     
  163.     def is_valid(self, value):
  164.         '''Check if this is a valid value for this option.'''
  165.         if self.allowed_values is None:
  166.             return False
  167.         
  168.         if self.multiple_values_allowed():
  169.             return self.is_valid_multiple(value)
  170.         else:
  171.             return self.is_valid_single(value)
  172.  
  173.     
  174.     def is_valid_multiple(self, value):
  175.         '''Return True iff value is a valid value for this option.
  176.         Use if multiple values are allowed.'''
  177.         if type(value) in MultiContainerTypes:
  178.             for val in value:
  179.                 if not self.is_valid_single(val):
  180.                     return False
  181.                     continue
  182.             
  183.             return True
  184.         
  185.         return self.is_valid_single(value)
  186.  
  187.     
  188.     def is_valid_single(self, value):
  189.         '''Return True iff value is a valid value for this option.
  190.         Use when multiple values are not allowed.'''
  191.         if type(self.allowed_values) == types.TupleType:
  192.             if value in self.allowed_values:
  193.                 return True
  194.             else:
  195.                 return False
  196.         elif self.is_boolean:
  197.             if value == True or value == False:
  198.                 return True
  199.             
  200.         if type(value) != type(self.value) and type(self.value) not in MultiContainerTypes:
  201.             if type(value) not in types.StringTypes or type(self.value) not in types.StringTypes:
  202.                 return False
  203.             
  204.         
  205.         if value == '':
  206.             return True
  207.         
  208.         avals = self._split_values(value)
  209.         if len(avals) == 1:
  210.             return True
  211.         else:
  212.             return False
  213.  
  214.     
  215.     def _split_values(self, value):
  216.         if not self.allowed_values:
  217.             return ('',)
  218.         
  219.         
  220.         try:
  221.             r = re.compile(self.allowed_values)
  222.         except:
  223.             print >>sys.stderr, self.allowed_values
  224.             raise 
  225.  
  226.         s = str(value)
  227.         i = 0
  228.         vals = []
  229.         while True:
  230.             m = r.search(s[i:])
  231.             if m is None:
  232.                 break
  233.             
  234.             vals.append(m.group())
  235.             delimiter = s[i:i + m.start()]
  236.             if self.delimiter is None and delimiter != '':
  237.                 self.delimiter = delimiter
  238.             
  239.             i += m.end()
  240.         return tuple(vals)
  241.  
  242.     
  243.     def as_nice_string(self, section = None):
  244.         '''Summarise the option in a user-readable format.'''
  245.         if section is None:
  246.             strval = ''
  247.         else:
  248.             strval = '[%s] ' % section
  249.         strval += '%s - "%s"\nDefault: %s\nDo not restore: %s\n' % (self.name, self.display_name(), str(self.default()), str(self.no_restore()))
  250.         strval += 'Valid values: %s\nMultiple values allowed: %s\n' % (str(self.valid_input()), str(self.multiple_values_allowed()))
  251.         strval += '"%s"\n\n' % str(self.doc())
  252.         return strval
  253.  
  254.     
  255.     def as_documentation_string(self, section = None):
  256.         '''Summarise the option in a format suitable for unmodified
  257.         insertion in HTML documentation.'''
  258.         strval = [
  259.             '<tr>']
  260.         if section is not None:
  261.             strval.append('\t<td>[%s]</td>' % (section,))
  262.         
  263.         strval.append('\t<td>%s</td>' % (self.name,))
  264.         ', '.join([] % []([ str(s) for s in self.valid_input() ]))
  265.         default = self.default()
  266.         strval.append('\t<td>%s</td>' % (default,))
  267.         strval.append('\t<td><strong>%s</strong>: %s</td>' % (self.display_name(), self.doc()))
  268.         strval.append('</tr>\n')
  269.         return '\n'.join(strval)
  270.  
  271.     
  272.     def write_config(self, file):
  273.         '''Output value in configuration file format.'''
  274.         file.write(self.name)
  275.         file.write(': ')
  276.         file.write(self.unconvert())
  277.         file.write('\n')
  278.  
  279.     
  280.     def convert(self, value):
  281.         '''Convert value from a string to the appropriate type.'''
  282.         svt = type(self.value)
  283.         if svt == type(value):
  284.             return value
  285.         
  286.         if type(self.allowed_values) == types.TupleType and value in self.allowed_values:
  287.             return value
  288.         
  289.         if self.is_boolean():
  290.             if str(value) == 'True' or value == 1:
  291.                 return True
  292.             elif str(value) == 'False' or value == 0:
  293.                 return False
  294.             
  295.             raise TypeError, self.name + ' must be True or False'
  296.         
  297.         if self.multiple_values_allowed():
  298.             if isinstance(self.allowed_values, types.StringTypes):
  299.                 vals = list(self._split_values(value))
  300.             elif isinstance(value, types.TupleType):
  301.                 vals = list(value)
  302.             else:
  303.                 vals = value.split()
  304.             if len(self.default_value) > 0:
  305.                 to_type = type(self.default_value[0])
  306.             else:
  307.                 to_type = types.StringType
  308.             for i in range(0, len(vals)):
  309.                 vals[i] = self._convert(vals[i], to_type)
  310.             
  311.             return tuple(vals)
  312.         else:
  313.             return self._convert(value, svt)
  314.         raise TypeError, self.name + ' has an invalid type.'
  315.  
  316.     
  317.     def _convert(self, value, to_type):
  318.         '''Convert an int, float or string to the specified type.'''
  319.         if to_type == type(value):
  320.             return value
  321.         
  322.         if to_type == types.IntType:
  323.             return locale.atoi(value)
  324.         
  325.         if to_type == types.FloatType:
  326.             return locale.atof(value)
  327.         
  328.         if to_type in types.StringTypes:
  329.             return str(value)
  330.         
  331.         raise TypeError, 'Invalid type.'
  332.  
  333.     
  334.     def unconvert(self):
  335.         '''Convert value from the appropriate type to a string.'''
  336.         if type(self.value) in types.StringTypes:
  337.             return self.value
  338.         
  339.         if self.is_boolean():
  340.             if self.value == True:
  341.                 return 'True'
  342.             else:
  343.                 return 'False'
  344.         
  345.         if type(self.value) == types.TupleType:
  346.             if len(self.value) == 0:
  347.                 return ''
  348.             
  349.             if len(self.value) == 1:
  350.                 v = self.value[0]
  351.                 if type(v) == types.FloatType:
  352.                     return locale.str(self.value[0])
  353.                 
  354.                 return str(v)
  355.             
  356.             strval = ''
  357.             if self.delimiter is None:
  358.                 if type(self.allowed_values) == types.TupleType:
  359.                     self.delimiter = ' '
  360.                 else:
  361.                     v0 = self.value[0]
  362.                     v1 = self.value[1]
  363.                     for sep in [
  364.                         ' ',
  365.                         ',',
  366.                         ':',
  367.                         ';',
  368.                         '/',
  369.                         '\\',
  370.                         None]:
  371.                         test_str = str(v0) + sep + str(v1)
  372.                         test_tuple = self._split_values(test_str)
  373.                         if test_tuple[0] == str(v0) and test_tuple[1] == str(v1) and len(test_tuple) == 2:
  374.                             break
  375.                             continue
  376.                     
  377.                     self.delimiter = sep
  378.             
  379.             for v in self.value:
  380.                 if type(v) == types.FloatType:
  381.                     v = locale.str(v)
  382.                 else:
  383.                     v = str(v)
  384.                 strval += v + self.delimiter
  385.             
  386.             strval = strval[:-len(self.delimiter)]
  387.         else:
  388.             strval = str(self.value)
  389.         return strval
  390.  
  391.     
  392.     def is_boolean(self):
  393.         '''Return True iff the option is a boolean value.'''
  394.         
  395.         try:
  396.             if type(self.allowed_values) == types.TupleType and len(self.allowed_values) > 0 and type(self.allowed_values[0]) == types.BooleanType:
  397.                 return True
  398.             
  399.             return False
  400.         except AttributeError:
  401.             if self.allowed_values == (False, True):
  402.                 return True
  403.             
  404.             return False
  405.  
  406.  
  407.  
  408.  
  409. class OptionsClass(object):
  410.     
  411.     def __init__(self):
  412.         self.verbose = None
  413.         self._options = { }
  414.         self.restore_point = { }
  415.         self.conversion_table = { }
  416.  
  417.     SECTCRE = re.compile('\\[(?P<header>[^]]+)\\]')
  418.     OPTCRE = re.compile('(?P<option>[^:=\\s][^:=]*)\\s*(?P<vi>[:=])\\s*(?P<value>.*)$')
  419.     
  420.     def update_file(self, filename):
  421.         '''Update the specified configuration file.'''
  422.         sectname = None
  423.         optname = None
  424.         out = TemporaryFile()
  425.         if os.path.exists(filename):
  426.             f = file(filename, 'r')
  427.         elif self.verbose:
  428.             print >>sys.stderr, 'Creating new configuration file',
  429.             print >>sys.stderr, filename
  430.         
  431.         f = file(filename, 'w')
  432.         f.close()
  433.         f = file(filename, 'r')
  434.         written = []
  435.         vi = ': '
  436.         while True:
  437.             line = f.readline()
  438.             if not line:
  439.                 break
  440.             
  441.             if line.strip() == '' or line[0] in '#;':
  442.                 out.write(line)
  443.                 continue
  444.             
  445.             if line.split(None, 1)[0].lower() == 'rem' and line[0] in 'rR':
  446.                 out.write(line)
  447.                 continue
  448.             
  449.             if line[0].isspace() and sectname is not None and optname:
  450.                 continue
  451.                 continue
  452.             mo = self.SECTCRE.match(line)
  453.             if mo:
  454.                 if sectname is not None:
  455.                     self._add_missing(out, written, sectname, vi, False)
  456.                 
  457.                 sectname = mo.group('header')
  458.                 optname = None
  459.                 if sectname in self.sections():
  460.                     out.write(line)
  461.                 
  462.             sectname in self.sections()
  463.             mo = self.OPTCRE.match(line)
  464.             if mo:
  465.                 (optname, vi, optval) = mo.group('option', 'vi', 'value')
  466.                 if vi in ('=', ':') and ';' in optval:
  467.                     pos = optval.find(';')
  468.                     if pos != -1 and optval[pos - 1].isspace():
  469.                         optval = optval[:pos]
  470.                     
  471.                 
  472.                 optval = optval.strip()
  473.                 if optval == '""':
  474.                     optval = ''
  475.                 
  476.                 optname = optname.rstrip().lower()
  477.                 if self._options.has_key((sectname, optname)):
  478.                     out.write(optname)
  479.                     out.write(vi)
  480.                     newval = self.unconvert(sectname, optname)
  481.                     out.write(newval.replace('\n', '\n\t'))
  482.                     out.write('\n')
  483.                     written.append((sectname, optname))
  484.                 
  485.             self._options.has_key((sectname, optname))
  486.         for sect in self.sections():
  487.             self._add_missing(out, written, sect, vi)
  488.         
  489.         f.close()
  490.         out.flush()
  491.         if self.verbose:
  492.             shutil.copyfile(filename, filename + '.bak')
  493.         
  494.         f = file(filename, 'w')
  495.         out.seek(0)
  496.         shutil.copyfileobj(out, f)
  497.         out.close()
  498.         f.close()
  499.  
  500.     
  501.     def _add_missing(self, out, written, sect, vi, label = True):
  502.         for opt in self.options_in_section(sect):
  503.             if (sect, opt) not in written and self.get(sect, opt) != self.default(sect, opt):
  504.                 if label:
  505.                     out.write('[')
  506.                     out.write(sect)
  507.                     out.write(']\n')
  508.                     label = False
  509.                 
  510.                 out.write(opt)
  511.                 out.write(vi)
  512.                 newval = self.unconvert(sect, opt)
  513.                 out.write(newval.replace('\n', '\n\t'))
  514.                 out.write('\n')
  515.                 written.append((sect, opt))
  516.                 continue
  517.         
  518.  
  519.     
  520.     def load_defaults(self, defaults):
  521.         '''Load default values (stored in Options.py).'''
  522.         for section, opts in defaults.items():
  523.             for opt in opts:
  524.                 klass = Option
  525.                 args = opt
  526.                 
  527.                 try:
  528.                     if issubclass(opt[0], Option):
  529.                         klass = opt[0]
  530.                         args = opt[1:]
  531.                 except TypeError:
  532.                     pass
  533.  
  534.                 o = klass(*args)
  535.                 self._options[(section, o.name)] = o
  536.             
  537.         
  538.  
  539.     
  540.     def set_restore_point(self):
  541.         '''Remember what the option values are right now, to
  542.         be able to go back to them, via revert_to_restore_point().
  543.  
  544.         Any existing restore point is wiped.  Restore points do
  545.         not persist over sessions.
  546.         '''
  547.         self.restore_point = { }
  548.         for key, opt_obj in self._options.iteritems():
  549.             self.restore_point[key] = opt_obj.get()
  550.         
  551.  
  552.     
  553.     def revert_to_restore_point(self):
  554.         '''Restore option values to their values when set_restore_point()
  555.         was last called.
  556.  
  557.         If set_restore_point() has not been called, then this has no
  558.         effect.  If new options have been added since set_restore_point,
  559.         their values are not effected.
  560.         '''
  561.         for key, value in self.restore_point.iteritems():
  562.             self._options[key].set(value)
  563.         
  564.  
  565.     
  566.     def merge_files(self, file_list):
  567.         for f in file_list:
  568.             self.merge_file(f)
  569.         
  570.  
  571.     
  572.     def convert_and_set(self, section, option, value):
  573.         value = self.convert(section, option, value)
  574.         self.set(section, option, value)
  575.  
  576.     
  577.     def merge_file(self, filename):
  578.         import ConfigParser
  579.         c = ConfigParser.ConfigParser()
  580.         c.read(filename)
  581.         for sect in c.sections():
  582.             for opt in c.options(sect):
  583.                 value = c.get(sect, opt)
  584.                 section = sect
  585.                 option = opt
  586.                 if not self._options.has_key((section, option)):
  587.                     pass
  588.                 None if option.startswith('x-') else self._options.has_key((section, option))
  589.                 self.convert_and_set(section, option, value)
  590.             
  591.         
  592.  
  593.     
  594.     def display_name(self, sect, opt):
  595.         '''A name for the option suitable for display to a user.'''
  596.         return self._options[(sect, opt.lower())].display_name()
  597.  
  598.     
  599.     def default(self, sect, opt):
  600.         '''The default value for the option.'''
  601.         return self._options[(sect, opt.lower())].default()
  602.  
  603.     
  604.     def doc(self, sect, opt):
  605.         '''Documentation for the option.'''
  606.         return self._options[(sect, opt.lower())].doc()
  607.  
  608.     
  609.     def valid_input(self, sect, opt):
  610.         '''Valid values for the option.'''
  611.         return self._options[(sect, opt.lower())].valid_input()
  612.  
  613.     
  614.     def no_restore(self, sect, opt):
  615.         '''Do not restore this option when restoring to defaults.'''
  616.         return self._options[(sect, opt.lower())].no_restore()
  617.  
  618.     
  619.     def is_valid(self, sect, opt, value):
  620.         '''Check if this is a valid value for this option.'''
  621.         return self._options[(sect, opt.lower())].is_valid(value)
  622.  
  623.     
  624.     def multiple_values_allowed(self, sect, opt):
  625.         '''Multiple values are allowed for this option.'''
  626.         return self._options[(sect, opt.lower())].multiple_values_allowed()
  627.  
  628.     
  629.     def is_boolean(self, sect, opt):
  630.         '''The option is a boolean value. (Support for Python 2.2).'''
  631.         return self._options[(sect, opt.lower())].is_boolean()
  632.  
  633.     
  634.     def convert(self, sect, opt, value):
  635.         '''Convert value from a string to the appropriate type.'''
  636.         return self._options[(sect, opt.lower())].convert(value)
  637.  
  638.     
  639.     def unconvert(self, sect, opt):
  640.         '''Convert value from the appropriate type to a string.'''
  641.         return self._options[(sect, opt.lower())].unconvert()
  642.  
  643.     
  644.     def get_option(self, sect, opt):
  645.         '''Get an option.'''
  646.         if self.conversion_table.has_key((sect, opt)):
  647.             (sect, opt) = self.conversion_table[(sect, opt)]
  648.         
  649.         return self._options[(sect, opt.lower())]
  650.  
  651.     
  652.     def get(self, sect, opt):
  653.         '''Get an option value.'''
  654.         if self.conversion_table.has_key((sect, opt.lower())):
  655.             (sect, opt) = self.conversion_table[(sect, opt.lower())]
  656.         
  657.         return self.get_option(sect, opt.lower()).get()
  658.  
  659.     
  660.     def __getitem__(self, key):
  661.         return self.get(key[0], key[1])
  662.  
  663.     
  664.     def set(self, sect, opt, val = None):
  665.         '''Set an option.'''
  666.         if self.conversion_table.has_key((sect, opt.lower())):
  667.             (sect, opt) = self.conversion_table[(sect, opt.lower())]
  668.         
  669.         if sect == 'Headers' and opt in ('notate_to', 'notate_subject'):
  670.             header_strings = (self.get('Headers', 'header_ham_string'), self.get('Headers', 'header_spam_string'), self.get('Headers', 'header_unsure_string'))
  671.             self._options[(sect, opt.lower())].set(val)
  672.             return None
  673.         
  674.         if self.is_valid(sect, opt, val):
  675.             self._options[(sect, opt.lower())].set(val)
  676.         else:
  677.             print >>sys.stderr, 'Attempted to set [%s] %s with invalid value %s (%s)' % (sect, opt.lower(), val, type(val))
  678.  
  679.     
  680.     def set_from_cmdline(self, arg, stream = None):
  681.         '''Set option from colon-separated sect:opt:val string.
  682.  
  683.         If optional stream arg is not None, error messages will be displayed
  684.         on stream, otherwise KeyErrors will be propagated up the call chain.
  685.         '''
  686.         (sect, opt, val) = arg.split(':', 2)
  687.         opt = opt.lower()
  688.         
  689.         try:
  690.             val = self.convert(sect, opt, val)
  691.         except (KeyError, TypeError):
  692.             msg = None
  693.             if stream is not None:
  694.                 self._report_option_error(sect, opt, val, stream, msg)
  695.             else:
  696.                 raise 
  697.         except:
  698.             stream is not None
  699.  
  700.         self.set(sect, opt, val)
  701.  
  702.     
  703.     def _report_deprecated_error(self, sect, opt):
  704.         print >>sys.stderr, 'Warning: option %s in section %s is deprecated' % (opt, sect)
  705.  
  706.     
  707.     def _report_option_error(self, sect, opt, val, stream, msg):
  708.         if sect in self.sections():
  709.             vopts = self.options(True)
  710.             vopts = _[1]
  711.             if opt not in vopts:
  712.                 print >>stream, 'Invalid option:', opt
  713.                 print >>stream, 'Valid options for', sect, 'are:'
  714.                 vopts = ', '.join(vopts)
  715.                 vopts = wrap(vopts)
  716.                 for line in vopts:
  717.                     print >>stream, '  ', line
  718.                 
  719.             else:
  720.                 print >>stream, 'Invalid value:', msg
  721.         else:
  722.             print >>stream, 'Invalid section:', sect
  723.             print >>stream, 'Valid sections are:'
  724.             vsects = ', '.join(self.sections())
  725.             vsects = wrap(vsects)
  726.             for line in vsects:
  727.                 print >>stream, '  ', line
  728.             
  729.  
  730.     
  731.     def __setitem__(self, key, value):
  732.         self.set(key[0], key[1], value)
  733.  
  734.     
  735.     def sections(self):
  736.         '''Return an alphabetical list of all the sections.'''
  737.         all = []
  738.         for sect, opt in self._options.keys():
  739.             if sect not in all:
  740.                 all.append(sect)
  741.                 continue
  742.         
  743.         all.sort()
  744.         return all
  745.  
  746.     
  747.     def options_in_section(self, section):
  748.         '''Return an alphabetical list of all the options in this section.'''
  749.         all = []
  750.         for sect, opt in self._options.keys():
  751.             if sect == section:
  752.                 all.append(opt)
  753.                 continue
  754.         
  755.         all.sort()
  756.         return all
  757.  
  758.     
  759.     def options(self, prepend_section_name = False):
  760.         '''Return an alphabetical list of all the options, optionally
  761.         prefixed with [section_name]'''
  762.         all = []
  763.         for sect, opt in self._options.keys():
  764.             if prepend_section_name:
  765.                 all.append('[' + sect + ']' + opt)
  766.                 continue
  767.             all.append(opt)
  768.         
  769.         all.sort()
  770.         return all
  771.  
  772.     
  773.     def display(self, add_comments = False):
  774.         '''Display options in a config file form.'''
  775.         output = StringIO.StringIO()
  776.         keys = self._options.keys()
  777.         keys.sort()
  778.         currentSection = None
  779.         for sect, opt in keys:
  780.             if sect != currentSection:
  781.                 if currentSection is not None:
  782.                     output.write('\n')
  783.                 
  784.                 output.write('[')
  785.                 output.write(sect)
  786.                 output.write(']\n')
  787.                 currentSection = sect
  788.             
  789.             if add_comments:
  790.                 doc = self._options[(sect, opt)].doc()
  791.                 if not doc:
  792.                     doc = 'No information available, sorry.'
  793.                 
  794.                 doc = re.sub('\\s+', ' ', doc)
  795.                 output.write('\n# %s\n' % ('\n# '.join(wrap(doc)),))
  796.             
  797.             self._options[(sect, opt)].write_config(output)
  798.         
  799.         return output.getvalue()
  800.  
  801.     
  802.     def _display_nice(self, section, option, formatter):
  803.         '''Display a nice output of the options'''
  804.         output = StringIO.StringIO()
  805.         if section is not None and option is not None:
  806.             opt = self._options[(section, option.lower())]
  807.             output.write(getattr(opt, formatter)(section))
  808.             return output.getvalue()
  809.         
  810.         all = self._options.keys()
  811.         all.sort()
  812.         for sect, opt in all:
  813.             if section is not None and sect != section:
  814.                 continue
  815.             
  816.             opt = self._options[(sect, opt.lower())]
  817.             output.write(getattr(opt, formatter)(sect))
  818.         
  819.         return output.getvalue()
  820.  
  821.     
  822.     def display_full(self, section = None, option = None):
  823.         '''Display options including all information.'''
  824.         return self._display_nice(section, option, 'as_nice_string')
  825.  
  826.     
  827.     def output_for_docs(self, section = None, option = None):
  828.         '''Return output suitable for inserting into documentation for
  829.         the available options.'''
  830.         return self._display_nice(section, option, 'as_documentation_string')
  831.  
  832.  
  833. HEADER_NAME = '[\\w\\.\\-\\*]+'
  834. HEADER_VALUE = '.+'
  835. INTEGER = '[\\d]+'
  836. REAL = '[\\d]+[\\.]?[\\d]*'
  837. BOOLEAN = (False, True)
  838. SERVER = '([\\w\\.\\-]+(:[\\d]+)?)'
  839. PORT = '[\\d]+'
  840. EMAIL_ADDRESS = '[\\w\\-\\.]+@[\\w\\-\\.]+'
  841. PATH = '[\\w \\$\\.\\-~:\\\\/\\*\\@\\=]+'
  842. VARIABLE_PATH = PATH + '%'
  843. FILE = '[\\S]+'
  844. FILE_WITH_PATH = PATH
  845. IP_LIST = '\\*|localhost|((\\*|[01]?\\d\\d?|2[04]\\d|25[0-5])\\.(\\*|[01]?\\d\\d?|2[04]\\d|25[0-5])\\.(\\*|[01]?\\d\\d?|2[04]\\d|25[0-5])\\.(\\*|[01]?\\d\\d?|2[04]\\d|25[0-5]),?)+'
  846. IMAP_FOLDER = '[^,]+'
  847. IMAP_ASTRING = []
  848. for i in range(1, 128):
  849.     if not (chr(i) in [
  850.         '"',
  851.         '\\',
  852.         '\n',
  853.         '\r']):
  854.         IMAP_ASTRING.append(chr(i))
  855.     
  856.  
  857. IMAP_ASTRING = '\\"?[' + re.escape(''.join(IMAP_ASTRING)) + ']+\\"?'
  858. RESTORE = True
  859. DO_NOT_RESTORE = False
  860.